BigQuery のループ制御文の使いどころを自分なりに整理してみた
こんにちは!エノカワです。
BigQuery にはループ処理を実現する制御文が用意されていますが、「こういうことをしたい場合、どの制御文を使えば良いんだっけ?」と迷った経験はありませんか?
(私だけ?)
ループ制御文の使いどころ
ということで、ループ制御文の使いどころを自分なりに整理してみました。
制御文 | 使いどころ | 特徴 |
---|---|---|
LOOP | 条件付きでループを抜ける必要がある場合 | - BREAK、LEAVE などでループを制御 - 反復回数が事前に分からない場合に適している |
REPEAT | 少なくとも1回はループ本体を実行したい場合 | - 条件判定は反復後に行われる - 初期化が不要な単純なループに適している |
WHILE | 事前条件を満たす間ループを実行したい場合 | - 条件判定が最初に行われる - ループ本体が全く実行されない可能性がある |
FOR...IN | 配列やクエリの結果セットなどの集合に対してループしたい場合 | - 集合の要素数分だけ反復が行われる - 各反復で要素値が自動的に割り当てられる |
それぞれの制御文の特徴を踏まえて、以下のようなポイントで使い分けができそうです。
- 無条件で反復したい場合は LOOP
- 初回実行が確実に必要な場合は REPEAT
- 条件を先に評価したい場合は WHILE
- 集合に対して反復したい場合は FOR...IN
また、以下の制御文を使うことで条件によってループを制御できるので、よりきめ細かなロジックを実装できます。
IF 文と組み合わせて使用します。LOOP, REPEAT, WHILE, FOR..IN いずれのループ制御でも使用できます。
使用例
以下、各制御文の特徴を掴むために構文と使用例を見てみましょう。
LOOP
構文
LOOP ループ本体; ... IF 条件式 THEN LEAVE; END IF; END LOOP;
条件式が真になるまでループ本体を繰り返し実行します。
使用例
デフォルト値 0 で宣言した変数x
が 10 以上になるまで繰り返します。
DECLARE x INT64 DEFAULT 0; LOOP SET x = x + 1; IF x >= 10 THEN LEAVE; END IF; END LOOP; SELECT x;
| x | | --- | | 10 |
REPEAT
構文
REPEAT ループ本体; UNTIL 条件式 END REPEAT;
ループ本体を1回実行した後、条件式が真になるまでループ本体を繰り返します。
使用例
デフォルト値 0 で宣言した変数x
が 3 以上になるまで繰り返します。
DECLARE x INT64 DEFAULT 0; REPEAT SET x = x + 1; SELECT x; UNTIL x >= 3 END REPEAT;
| x | | --- | | 1 | | x | | --- | | 2 | | x | | --- | | 3 |
BREAK
またはLEAVE
を使用して、ループを早めに抜けることもできます。
以下では、変数x
が 偶数 の場合にループを抜けています。
DECLARE x INT64 DEFAULT 0; REPEAT SET x = x + 1; SELECT x; IF MOD(x, 2) = 0 THEN BREAK; END IF; UNTIL x >= 3 END REPEAT;
| x | | --- | | 1 | | x | | --- | | 2 |
WHILE
構文
WHILE 条件式 DO ループ本体; END WHILE;
条件式が真の間、ループ本体を繰り返します。
使用例
デフォルト値 TRUE で宣言した変数heads
が FALSE になるまで繰り返します。
DECLARE heads BOOL DEFAULT TRUE; DECLARE coin_flip ARRAY<STRING>; WHILE heads DO SET heads = RAND() < 0.5; SET coin_flip = ARRAY_CONCAT(coin_flip, [IF(heads, 'Heads!', 'Tails!')]); END WHILE; SELECT result FROM UNNEST(coin_flip) AS result;
| result | | ------ | | Heads! | | Heads! | | Tails! |
条件によっては、ループ本体が全く実行されない可能性もあります。
以下では、変数heads
のデフォルト値を FALSE で宣言しているので、ループ本体が実行されません。
DECLARE heads BOOL DEFAULT FALSE; DECLARE coin_flip ARRAY<STRING>; WHILE heads DO SET heads = RAND() < 0.5; SET coin_flip = ARRAY_CONCAT(coin_flip, [IF(heads, 'Heads!', 'Tails!')]); END WHILE; SELECT result FROM UNNEST(coin_flip) AS result;
FOR...IN
構文
FOR レコード IN (式) DO ループ本体; END FOR;
式で生成される行に対してループ本体を実行します。
式は配列やクエリ結果のデータセットにも対応しています。
使用例
bigquery-public-data.samples.shakespeare
のクエリ結果の レコードの数 だけ繰り返します。
FOR record IN (SELECT word, word_count FROM bigquery-public-data.samples.shakespeare LIMIT 5) DO SELECT record.word, record.word_count; END FOR;
| word | word_count | | ------- | ---------- | | LVII | 1 | | word | word_count | | ------- | ---------- | | augurs | 1 | | word | word_count | | ------- | ---------- | | dimm'd | 1 | | word | word_count | | ------- | ---------- | | plagues | 1 | | word | word_count | | ------- | ---------- | | treason | 1 |
配列の要素の数だけ繰り返すこともできます。
以下では、配列fruits
の数だけ繰り返しています。
DECLARE fruits ARRAY<STRING>; SET fruits = ['Apple', 'Banana', 'Orange', 'Grapes']; FOR fruit IN (SELECT * FROM UNNEST(fruits) AS name) DO SELECT fruit.name; END FOR;
| name | | ------ | | Apple | | name | | ------ | | Banana | | name | | ------ | | Orange | | name | | ------ | | Grapes |
まとめ
以上、BigQuery のループ制御文の使いどころを自分なりに整理してみました。
自分自身への備忘録的な記事になってしまいましたが、他の方にも参考になれば幸いです!